// 不仅仅是函数之间跳转，将main作为调度器实现对多个协程的调度
#include <stdio.h>
#include <ucontext.h>

ucontext_t uctx[3];
ucontext_t main_ctx;
// 或者 struct ucontext

int count = 0;

// coroutine 1
void fun1(void)
{
    printf("调用函数fun1\n");
    while (count < 20)
    {
        printf("fun1 count[%d] swap fun2\n", ++count);
        swapcontext(&uctx[0], &main_ctx); // yield，协程让出
    }
}

// coroutine 2
void fun2(void)
{
    printf("调用函数fun2\n");
    while (count < 20)
    {
        printf("fun2 count[%d] swap fun3\n", ++count);
        swapcontext(&uctx[1], &main_ctx);
    }
}

// coroutine 3
void fun3(void)
{
    printf("调用函数fun3\n");
    while (count < 20)
    {
        printf("fun3 count[%d] swap fun1\n", ++count);
        swapcontext(&uctx[2], &main_ctx);
    }
}

// schedule，类似于调度器
typedef void (*func)(void);
int main()
{
    // 设置协程栈,注意类型是char
    char stacks[3][2048] = {0};
    // 设置协程函数指针
    for (int i = 0; i < 3; i++)
    {
        // 获取当前上下文
        getcontext(&uctx[i]);
        uctx[i].uc_stack.ss_sp = stacks[i];
        uctx[i].uc_stack.ss_size = sizeof(stacks[i]);
        // 设置下一次跳转的函数
        uctx[i].uc_link = &main_ctx; // 作用是切换上下文执行结束后跳转到指定的上下文中
    }
    makecontext(&uctx[0], fun1, 0); // 需要设置下一次跳转函数的uctx上下文和函数指针
    makecontext(&uctx[1], fun2, 0);
    makecontext(&uctx[2], fun3, 0);

    // 由主函数进行调度
    printf("main schedule start\n");
    while (count < 30)
    {
        // 简单的调度逻辑，这里就能看到函数调用是同步的，内部是异步执行的
        // 由于swap会保存当前函数的上下文，所以协程主动/被动切回之后会回到这里
        swapcontext(&main_ctx, &uctx[count % 3]); // resume,调度器重新开始
    }
    printf("\n");
    return 0;
}